﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Models;
using DAL;
using MySocketHelper;
namespace BLL
{
    public class RemoteIOManager
    {
        private RemoteIOService objRemoteIOService = new RemoteIOService();
        private List<byte> buffer = new List<byte>(4096);//默认分配1页内存，并始终限制不允许超过   
        private byte[] binary_data = new byte[12];//AA 44 05 01 02 03 04 05 EA 
        
        private bool Listening = false;
        #region 定义委托和事件

        public delegate void SendRemoteDataEventHandler(AsyncUserToken token, byte address); //声明一个向远程IO发送信息的委托
        public event SendRemoteDataEventHandler OnSendRemoteData;//声明一个向远程IO发送信息的事件
        #endregion

        #region 协议解析
        /// <summary>
        /// 远程IO协议解析
        /// </summary>
        /// <param name="data">接收数据</param>
        /// <param name="ip">接收数据的IP地址</param>
        /// <returns>远程IO详细信息</returns>
        public List<ExCall> ResolutionProtocol(byte[] data, AsyncUserToken token)
        {
            ExCall objExCall = new ExCall();
            List<ExCall> list = new List<ExCall>();
            //<协议解析>   
            bool data_catched = false;//缓存记录数据是否捕获到   
            //1.缓存数据   
            token.Buffer.AddRange(data);
            if (Listening == false)
            {
                //2.完整性判断   
                while (token.Buffer.Count >= 8)//至少要包含头（2字节）+校验（1字节）   
                {
                    //2.1 查找数据头 + 数据尾  
                    if (token.Buffer[0] == 0x00 && token.Buffer[1] == 0x05)
                    {
                        //2.2 探测缓存数据是否有一条数据的字节，如果不够，就不用费劲的做其他验证了   
                        //前面已经限定了剩余长度>=4，那我们这里一定能访问到buffer[2]这个长度  
                        int len = 8;//数据长度   
                        //数据完整判断第一步，长度是否足够   
                        //len是数据段长度,4个字节是while行注释的3部分长度   
                        if (token.Buffer. Count < len) break;//数据不够的时候什么都不做   
                        
                        //至此，已经被找到了一条完整数据。我们将数据直接分析，或是缓存起来一起分析   
                        //我们这里采用的办法是缓存一次，好处就是如果你某种原因，数据堆积在缓存buffer中   
                        //已经很多了，那你需要循环的找到最后一组，只分析最新数据，过往数据你已经处理不及时   
                        //了，就不要浪费更多时间了，这也是考虑到系统负载能够降低。   
                        token.Buffer.CopyTo(0, binary_data, 0, len);//复制一条完整数据到具体的数据缓存   
                        data_catched = true;
                        token.Buffer.RemoveRange(0, len);//正确分析一条数据，从缓存中移除数据。   
                    }
                    else
                    {
                        //这里是很重要的，如果数据开始不是头，则删除数据   
                        //buffer.RemoveAt(0);
                        token.Buffer.RemoveRange(0, 2);
                    }
                    // }
                    //分析数据   
                    if (data_catched)
                    {
                        Listening = true;
                        //</协议解析>   
                        ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 
                        if (binary_data[4] == 0xFF)
                        {
                            objExCall = GetRemoteIOByIP(token.IPAddress.ToString(), binary_data[3]); //根据呼叫的IP和端口号获取呼叫信息
                            if (objExCall != null && objExCall.IP != null) //呼叫的IO没有存在则不显示，只显示存在的IO
                            {
                                list.Add(objExCall);
                                AddUnfinishCall(objExCall);//添加一个呼叫信息到数据库
                            }
                            //发送确认呼叫成功数据
                            if (OnSendRemoteData != null)
                            {
                                OnSendRemoteData(token, binary_data[3]);
                            } 
                        }
                       // else objExCall = null;
                        Listening = false;
                    }
                }
            }
            return list;
            // builder.Clear();//清除字符串构造器的内容   
        }
        #endregion

        #region 远程IO数据解析12字节
        /// <summary>
        /// 远程IO协议解析
        /// </summary>
        /// <param name="data">接收数据</param>
        /// <param name="ip">接收数据的IP地址</param>
        /// <returns>远程IO详细信息</returns>
        public List<ExCall> ResolutionProtocol2(byte[] data, AsyncUserToken token)
        {
            ExCall objExCall = new ExCall();
            List<ExCall> list = new List<ExCall>();
            //<协议解析>   
            bool data_catched = false;//缓存记录数据是否捕获到   
            //1.缓存数据   
            token.Buffer.AddRange(data);
            if (Listening == false)
            {
                //2.完整性判断   
                while (token.Buffer.Count >= 12)//至少要包含头（2字节）+校验（1字节）   
                {
                    //2.1 查找数据头 + 数据尾  
                    if (token.Buffer[5] == 0x06 && token.Buffer[7] == 0x05)
                    {
                        //2.2 探测缓存数据是否有一条数据的字节，如果不够，就不用费劲的做其他验证了   
                        //前面已经限定了剩余长度>=4，那我们这里一定能访问到buffer[2]这个长度  
                        int len = 12;//数据长度   
                        //数据完整判断第一步，长度是否足够   
                        //len是数据段长度,4个字节是while行注释的3部分长度   
                        if (token.Buffer.Count < len) break;//数据不够的时候什么都不做   

                        //至此，已经被找到了一条完整数据。我们将数据直接分析，或是缓存起来一起分析   
                        //我们这里采用的办法是缓存一次，好处就是如果你某种原因，数据堆积在缓存buffer中   
                        //已经很多了，那你需要循环的找到最后一组，只分析最新数据，过往数据你已经处理不及时   
                        //了，就不要浪费更多时间了，这也是考虑到系统负载能够降低。   
                        token.Buffer.CopyTo(0, binary_data, 0, len);//复制一条完整数据到具体的数据缓存   
                        data_catched = true;
                        token.Buffer.RemoveRange(0, len);//正确分析一条数据，从缓存中移除数据。   
                    }
                    else
                    {
                        //这里是很重要的，如果数据开始不是头，则删除数据   
                        //buffer.RemoveAt(0);
                        token.Buffer.RemoveRange(0, 7);
                    }
                    // }
                    //分析数据   
                    if (data_catched)
                    {
                        Listening = true;
                        //</协议解析>   
                        ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 
                        if (binary_data[10] == 0xFF)
                        {
                            objExCall = GetRemoteIOByIP(token.IPAddress.ToString(), binary_data[9]); //根据呼叫的IP和端口号获取呼叫信息
                            if (objExCall != null && objExCall.IP != null) //呼叫的IO没有存在则不显示，只显示存在的IO
                            {
                                list.Add(objExCall);
                                AddUnfinishCall(objExCall);//添加一个呼叫信息到数据库
                            }
                        }
                        // else objExCall = null;
                        Listening = false;
                    }
                }
            }
            return list;
            // builder.Clear();//清除字符串构造器的内容   
        }

        #endregion
        public List<ExCall> GetAllRemoteIO()
        {
            return objRemoteIOService.GetAllRemoteIO();
        }
        public List<ExCall> GetRemoteIO()
        {
            return objRemoteIOService.GetRemoteIO();
        }
        public ExCall GetRemoteIOByIP(string ip, int port)
        {
            return objRemoteIOService.GetRemoteIOByIP(ip,port);
        }
        public void AddStandbyCall(DataGridView dgv, List<ExCall> list)
        {
            dgv.Invoke(new Action<List<ExCall>> ((s)=>{dgv.DataSource = null;dgv.DataSource = s ;}),list);
        }
        public int AddRemoteIO(ExCall objExCall)
        {
            if (objRemoteIOService.IsExistsIP(objExCall.IP, objExCall.Port.ToString()) >= 1)
            {
                throw new Exception("IP："+objExCall.IP +"端口："+objExCall.PortName +"已存在");
            }
            return objRemoteIOService.AddRemoteIO(objExCall);
        }
        public int DeleteRemoteIO(string remoteId)
        {
            return objRemoteIOService.DeleteRemoteIO(remoteId);
        }
        public int UpdateRemoteIO(ExCall objExCall)
        {
            return objRemoteIOService.UpdateRemoteIO(objExCall);
        }
        public List<ExCall> GetUnfinishCallByTime(DateTime dateTime)
        {
            return objRemoteIOService.GetUnfinishCallByTime(dateTime);
        }
        public int DeleteUnfinishCall(ExCall objExCall)
        { 
            return objRemoteIOService.DeleteUnfinishCall(objExCall);
        }
        public bool DeleteUnfinishCallByTran(List<ExCall> list)
        {
            return objRemoteIOService.DeleteUnfinishCallByTran(list);
        }
        public int AddUnfinishCall(ExCall objExCall)
        {
            return objRemoteIOService.AddUnfinishCall(objExCall);
        }
        public bool AddFinishCallByTran(List<ExCall> list)
        {
            return objRemoteIOService.AddFinishCallByTran(list);
        }
        public List<ExCall> GetFinishCallByTime(DateTime dateTime)
        {
            return objRemoteIOService.GetFinishCallByTime(dateTime);
        }
          /// <summary>
        /// 按时间删除已完成的信息
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public int DeleteFinishCallByTime(string time)
        {
            return objRemoteIOService.DeleteFinishCallByTime(time);
        }
        public List<ExCall> GetRemoteName()
        {
            return objRemoteIOService.GetRemoteName();
        }
    }
}
